package com.herui.ota.service.iml;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ConcurrentHashSet;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.herui.ota.dao.mysql.DeviceMapper;
import com.herui.ota.entity.Device;
import com.herui.ota.entity.DeviceOta;
import com.herui.ota.enums.OpsTypeEnum;
import com.herui.ota.enums.ResponseEnum;
import com.herui.ota.exception.ServiceException;
import com.herui.ota.pojo.form.DeviceFilterForm;
import com.herui.ota.pojo.form.DeviceForm;
import com.herui.ota.service.*;
import com.herui.ota.utils.AddressUtils;
import com.mlnx.common.form.PageForm;
import com.mlnx.common.utils.FieldUtils;
import com.mlnx.common.utils.MyLog;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * author name: amanda.shan
 * create time: 2023-10-26 16:51:33
 */
@Service
public class DeviceServiceIml extends BaseService<DeviceMapper, Device> implements DeviceService {

    MyLog log = MyLog.getLog(getClass());

    public final String separate = "-";

    @Autowired
    private DeviceOtaService deviceOtaService;
    @Autowired
    private DeviceNewDailyService deviceNewDailyService;
    @Autowired
    private DeviceOtaEventService deviceOtaEventService;

    @Autowired
    private DeviceTreeService deviceTreeService;
    @Autowired
    private DeviceOtaChannelService deviceOtaChannelService;


    @Autowired
    private OpsRecordService opsRecordService;

    // key是设备型号  value是版本号
    private Set<String> channelChangeSet = new ConcurrentHashSet<>();
    // 每日区域新增
    private Map<String, AtomicInteger> typeAreaCountMap = new ConcurrentHashMap<>();

    private ExecutorService executorService;

    @PostConstruct
    public void init() {
        int coreThreadNum = Runtime.getRuntime().availableProcessors();
        executorService = Executors.newFixedThreadPool(coreThreadNum * 2);

//        typeAreaCountMap.put("type1"+separate+"中国", new AtomicInteger(3));

        resetTree();

        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    if (channelChangeSet.size() > 0) {
                        for (String channel : channelChangeSet) {
                            int count = count(new QueryWrapper<Device>().eq("channel", channel));
                            deviceOtaChannelService.updateCount(channel, count);
                            channelChangeSet.remove(channel);
                        }
                    }

                    if (typeAreaCountMap.size() > 0) {
                        for (String typeArea : typeAreaCountMap.keySet()) {
                            AtomicInteger atomicInteger = typeAreaCountMap.get(typeArea);
                            String[] split = typeArea.split(separate);
                            String type = split[0];
                            String area = split[1];
                            int count = atomicInteger.getAndSet(0);
                            try {
                                deviceNewDailyService.addCount(type,area, count);
                            }catch (Exception e){
                                log.error(e, "更新每日新增数量异常");
                                atomicInteger.addAndGet(count);
                            }

                        }
                    }
                } catch (Exception e) {
                    log.error(e, "设备数量更新异常");
                }
            }
        }, 0, 2000);
    }

    @Autowired
    @Override
    public void setBaseMapper(DeviceMapper baseMapper) {
        super.setBaseMapper(baseMapper);
    }

    @Override
    public IPage page(PageForm pageForm, Object filter) throws IllegalAccessException {

        QueryWrapper<Device> queryWrapper = new QueryWrapper<>();

        DeviceFilterForm filterForm = (DeviceFilterForm) filter;
        List<String> treeFilters = filterForm.getTreeFilter();
        if (treeFilters != null && treeFilters.size() > 0){
            queryWrapper.and(wrapper -> {
                for (String treeFilter: treeFilters){
                    wrapper.or(queryWrapper1 -> {
                        String[] split = treeFilter.split("-");
                        String[] keys = {"brand", "print_type", "market", "series", "version", "type"};
                        for (int i = 0; i < split.length; i++) {
                            queryWrapper1.eq(keys[i], split[i]);
                        }
                    });
                }
            });

        }

        String[] filedName = FieldUtils.getFiledName(filter);
        String[] var4 = filedName;
        int var5 = filedName.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            String file = var4[var6];
            Object value = FieldUtils.getFieldValueByName(file, filter);

            if (file.equals("bluName") && value != null){
                queryWrapper.like("blu_name", value);
            }
            else if (!file.equals("treeFilter")){
                if (value != null) {
                    queryWrapper.eq(FieldUtils.humpToLine2(file), value);
                }
            }
        }

        queryWrapper.orderByDesc("create_time");

        String customSqlSegment = queryWrapper.getCustomSqlSegment();
        log.info("device page customSqlSegment:{}", customSqlSegment);

        IPage page = this.page(new Page(pageForm.getCurrent(), pageForm.getSize()), queryWrapper);
        return page;
    }

    @Transactional
    @Override
    public void saveDevice(HttpServletRequest request, DeviceForm deviceForm) {

        if (StringUtils.isEmpty(deviceForm.getBluName())) {
            throw new ServiceException(ResponseEnum.PARAM_ERROR);
        }

        Device device = getOne(new QueryWrapper<Device>().eq("blu_name", deviceForm.getBluName()));
        if (device != null) {
            boolean change = true;
            if (!StringUtils.isEmpty(deviceForm.getChannel()) && !device.getChannel().equals(deviceForm.getChannel())) {
                change = true;
            }
            BeanUtil.copyProperties(deviceForm, device);
            updateById(wrapperEditor(device));
            if (change) {
                channelChangeSet.add(deviceForm.getChannel());
            }
        } else {
            if (StringUtils.isEmpty(deviceForm.getType()) || StringUtils.isEmpty(deviceForm.getVersion())) {
                throw new ServiceException(ResponseEnum.PARAM_ERROR);
            }

            device = new Device();
            BeanUtil.copyProperties(deviceForm, device);
            device = (wrapperCreater(device));
            executorService.submit(new AddDeviceTask(AddressUtils.getIpAddr(request), device, deviceForm.isSucess()));
        }
        deviceTreeService.saveTree(device.getTreeInfo());
    }

    @Override
    public boolean updateById(Device entity) {
        boolean b = super.updateById(wrapperEditor(entity));
        opsRecordService.save(OpsTypeEnum.UPDATE_DEVICE, entity.getId(), JSON.toJSONString(entity));
        deviceOtaEventService.save(entity, true);
        return b;
    }

    @Override
    public boolean removeById(Serializable id) {
        Device device = getById(id);
        opsRecordService.save(OpsTypeEnum.DELETE_DEVICE, device.getId(), JSON.toJSONString(device));
        return super.removeById(id);
    }

    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {

        idList.stream().forEach(id ->{
            Device device = getById(id);
            opsRecordService.save(OpsTypeEnum.DELETE_DEVICE, device.getId(), JSON.toJSONString(device));
        });

        return super.removeByIds(idList);
    }

    @Override
    public int allDeviceCount() {
        return count(new QueryWrapper<>());
    }

    @Override
    public void resetTree() {
        List<Device> list = list();
        List<String> collect = list.stream().map(deviceOta -> deviceOta.getTreeInfo()).collect(Collectors.toList());
        deviceTreeService.resetAll(collect);
    }

    @Override
    public Date activeDevice(String bluName) {
        Device device = getOne(new QueryWrapper<Device>().eq("blu_name", bluName));
        if (device != null && device.getActiveTime() == null){
            Device device1 = new Device();
            device1.setId(device.getId());
            device1.setActiveTime(new Date());
            updateById(device1);
            return device1.getActiveTime();
        }

        return device.getActiveTime();
    }

    @Override
    public void upgradeDevice(String bluName, boolean sucess) {
        Device device = getOne(new QueryWrapper<Device>().eq("blu_name", bluName));
        if (device != null){
            opsRecordService.save(OpsTypeEnum.UPGRADE_DEVICE, device.getId(), sucess+"");
        }
    }

    public class AddDeviceTask implements Runnable {

        private String ip;
        private Device device;

        private boolean sucess;

        public AddDeviceTask(String ip, Device device, boolean sucess) {
            this.ip = ip;
            this.device = device;
            this.sucess = sucess;
        }

        @Override
        public void run() {

            try {
                log.info("ip:{} 添加设备:{}", ip, device);

                Device d = getOne(new QueryWrapper<Device>().eq("blu_name", this.device.getBluName()));
                if (d == null) {
                    String area = AddressUtils.getAreaByIp(ip);
                    log.debug("获取 ip:{}  地址:{}", ip, area);
                    this.device.setArea(area);
                    save(this.device);
                    deviceOtaEventService.save(this.device, sucess);
                    if (StringUtils.isEmpty(device.getChannel())){
                        channelChangeSet.add(device.getChannel());
                    }

                    String key = this.device.getType() + separate + area;
                    AtomicInteger atomicInteger = typeAreaCountMap.get(key);
                    if (atomicInteger == null) {
                        atomicInteger = new AtomicInteger(0);
                        typeAreaCountMap.put(key, atomicInteger);
                    }
                    atomicInteger.incrementAndGet();

                    opsRecordService.save(OpsTypeEnum.CREATE_DEVICE, device.getId(), JSON.toJSONString(device));
                }
            } catch (Exception e) {
                log.error(e, "");
            }
        }
    }

}

